Mise à jour le 13/11/2021
PHP 8.0 Un café bien sucré !

PHP 8.0 Un café bien sucré !

1. Introduction

Il y a deux bonnes nouvelles à cette version de PHP, la première est que l'équipe de développement prouve qu'elle se bouge le cul et que la version 7 n'était pas juste un coup d'essai, la seconde est que la compilation JIT vend du rêve : on souhaite tous que sans rien faire à part un apt upgrade, notre code -même moche- s'execute beaucoup plus vite ; c'est bien arrivé avec PHP 7 !

Concernant les autres nouveautés, sans dire que la plupart ne sert pas à grand chose, d'autres sont potentiellement risquées à mettre en place.

Je reprends ici l'article que j'ai vu présentant certaines mises à jour de PHP 8.0, je vous invite à le lire avant cette page : https://hoa.ro/fr/blog/2020-11-26-php-8-0-is-out/

2. Les nouveautés une par une

2.1 Les arguments nommés

Alors que Java fait ce qu'on appelle du polymorphisme et permet de créer des méthodes du même nom qui traitent d'objets de classe ou de type differents, l'équipe derrière PHP a préféré pallier aux problèmes d'utilisation qu'engendre les arguments facultatifs en introduisant les arguments nommés, le projet était dans les clous depuis 2013, c'est dire la volonté de l'équipe de développer ce truc.

Cette nouvelle version permet, lors de l'appel d'une fonction, de dire quel argument prend quelle valeur, cela permet donc d'éviter de copier/coller les valeurs par défaut de tous les arguments qu'on ne souhaite pas utiliser pour ne modifier que le dernier (ou l'un des suivants), technique donc assez dangereuse puisque, si via une mise à jour du langage, la valeur du paramètre par défaut change, il faudra peut être repassé sur notre code.
Avec les arguments nommés, on doit donc désormais copier coller le nom du paramètre, la bonne affaire !

Autant donner mon avis : c'est continuer à patauger dans la boue que d'utiliser les arguments nommés à tire la rigaud pour pallier aux fonctions natives et historiques ayant trop d'arguments facultatifs.

Ce qui me semble plus judicieux : créer des services et manipuler ces fonctions PHP natives qui ont beaucoup de paramètres facultatifs en jouant sur la valeur des attributs de l'objet qui encapsulera la fonction.
Dit comme cela, c'est très lourd et évidemment si on souhaite utiliser une fonction PHP une seule fois dans une commande par exemple, il est peut être mieux d'utiliser les arguments nommés. Autrement dit, ce n'est qu'une question de mesure et de bon sens.
Il serait assez farfelu par ailleurs d'encapsuler toutes les fonctions de PHP dans des classes. Même si c'est ce que font déjà d'autres langages comme le JS (ex: Math) ou le Java (String).

Certaines fonctions comme la fonction htmlspecialchars mériteraient clairement d'être encapsulées pour éviter de retrouver cette fonction à des milliers d'endroits du code. Ex, la classe PHPEngine du composant Templating de Symfony.

Donc le bon sens pour deux cas de figure :
* vous souhaitez utiliser une fonction native de manière exceptionnelle (dans du code poubelle, dans du code one shoot, dans un algorithme très précis) : OK pour la fonction native et ses arguments nommés
* vous souhaitez utiliser une fonction native de manière fréquente : encapsulez-la dans un service !

2.2 Les attributs

Alors là, prudence de chez prudence. La configuration des routes est un très bon exemple, on pourrait le faire en xml, en yaml, en annotation, voilà qu'on peut le faire en attribut. C'est pas loin de la boite de pandore ce qu'ils nous ont pondu là. D'un point de vue personnel, je ne souhaite pas être le premier à me casser les dents là dessus.

Petit détail amusant : on se dit depuis des années qu'il faut arreter d'utiliser le @ qui permet de planquer les erreurs PHP, encore plus pertinent depuis qu'ils ont catchés toutes ces erreurs pour nous permettre de les récupérer sous la forme d'exception. Dire qu'on n'utilise pas le @ parce qu'il est déjà utilisé pour quelque chose de mauvais, c'est d'autant plus dommage. Il aurait fallu qu'ils nous disent "Dès PHP 8, il n'est plus possible d'utiliser le @ pour rendre silencieuse les erreurs". Ils auraient pu alors l'utiliser pour les annotations.

2.3 Les types d’union

Cela rejoint mon avis sur les arguments nommés, faire une méthode qui accepte du poulet/du cochon/la valeur 8 et enfin le "j'en sais rien" derrière le mixed, ce n'est vraiment pas ce que je trouve de plus élégant. Le typage fort OUI, à plus forte raison quand on souhaite contrôler ce qui rentre dans les méthodes de nos classes, si c'est pour accepter tout et n'importe quoi en valeur d'argument, autant effectivement ne rien mettre ou mettre du mixed.
Là encore, le polymorphisme me semblait une solution bien plus adaptée.

2.3.1 Comparaison polymorphisme VS Type d'union

Si le polymorphisme existait en PHP :

interface MyClass
{
    public function myMethod(int $arg);
    public function myMethod(string $arg);
}


Voilà ce que qu'on peut faire en PHP 8.0 :

interface MyClass
{
    public function myMethod(int|string $arg);
}


Il n'y a alors pas le choix, il faudra forcément distinguer les différents types dans l'implémentation (ou laisser la magie du composant ou de PHP faire le cast lui même, ce qui n'est pas terrible.).

2.3.2 Petite apparté pour un cas similaire

Même chose pour le try catch \Exception $e, quand on écrit ceci, c'est surtout de la paresse qui s'exprime et si l'excuse c'est qu'on ne sait pas ce que renvoie telle ou telle librairie comme exception, c'est peut être qu'on n'a pas eu la patience de regarder les cas d'erreurs en détail et donc au final, l'utilisateur de l'application verra un beau message lui indiquant qu'une erreur a eu lieu et que toute l'équipe est sur le pont pour la résoudre, ce qui est bien entendu un mensonge.

2.4 Déclaration des attributs dans le constructeur

Alors...oui mais avec parcimonie. Ici aussi c'est du sucre syntaxique, on gagne un peu de temps et on évite de copier coller le nom de l'attribut.
Mais, certains attributs ne sont pas forcément setté par le constructeur, donc cela veut dire qu'il y aura du code dans et en dehors du constructeur, ce qui demandera donc au développeur de regarder à la fois en tête de classe et dans la signature du constructeur, autant dire que pour le côté confort de lecture, on repassera.

2.5 Nouvelles fonctions str_*

Mieux vaut tard que jamais. Cela ajoute "peut-être" un gain de performance, à voir. A noter qu'on persiste dans le Snake Case, alors que la tendance est depuis quelques temps au Camel Case (je n'ai pas de préférence entre les deux, mais j'aimerais pour le plaisir éviter de mélanger les deux entre le langage natif et tel ou tel composant).

2.6 Nouvelle interface Stringable

Le _toString est quelque chose qui ne devrait être utilisé qu'en dev, tout est dit.

2.7 L’opérateur nullsafe

Je dois dire que ce sucre syntaxique là est plaisant mais à utiliser avec parcimonie car comme le @, c'est un coup à se retrouver avec des dizaines de faux '?' qu'un développeur aura mis pour résoudre des bugs alors que peut être que le bug réel est avéré : ex: si le client n'a pas d'adresse postal alors qu'il a passé sa commande et qu'il souhaite être livré, ce n'est pas trop la peine de corriger le bout de code qui fait un getAdress()->getCP() ; non, il faut :
1. mettre à jour la donnée pour renseigner son adresse
2. mettre à jour le code qui aurait dû la renseigner au moment de la commande, quite à ne pas confirmer la commande par ailleurs

2.8 Lever des exceptions dans les expressions

Je ne suis pas ultra fan des expressions inlines car elles sont moins lisibles et me semblent plus difficiles à débugguer, mais cela n'est pas génant à voir.

2.9 match, le cousin du switch

Encore du sucre, mais plutôt utile.
Dans la plupart des cas cependant, un switch peut aussi faire plusieurs affectations de valeurs, avec le match, on serait obligé de faire du copier/coller tandis qu'avec le switch, chaque test n'est fait qu'une fois.

Ex:

Avec un switch

<?php
$myLang = 'francais';

switch($myLang) {
    case 'francais':
    case 'marseillais':
        $myCountry = 'france';
        $myLocale = 'fr_FR';
        break;
    default:
    case 'anglais':
        $myCountry = 'england';
        $myLocale = 'en_EN';
        break;
}

Avec un match

<?php
$myCountry = match($myLang) {
    'francais' ,  'marseillais' => 'france',
    'anglais', default => 'england',
};

$myLocale = match($myLang) {
    'francais', 'marseillais'  => 'fr_FR',
    'anglais', default  => 'en_EN',
};

Ici, même si on réplique le test, surement négligeable au niveau du temps d'execution, mais si on ajoutait une langue, il faudrait modifier le code à deux endroits.

3. Conclusion

Cette version de PHP 8.0 démontre que le développement de PHP continue. On appréciera l'effort que font les développeurs pour simplifier l'utilisation du langage et le rendre plus mature. On regrettera cependant que certaines nouveautés reposent encore sur des bases pointées du doigt depuis longtemps par les développeurs comme très discutables (erreurs @, nombre d'arguments facultatifs, nommage, le type mixed).